home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / suck-2.6 / suck-2 / suck-2.6.3 / killfile.c < prev    next >
C/C++ Source or Header  |  1996-05-07  |  22KB  |  769 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <netdb.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <ctype.h>
  7.  
  8. #include "config.h"
  9. #include "both.h"
  10. #include "suck.h"
  11. #include "suckutils.h"
  12. #include "killfile.h"
  13. #ifdef TIMER
  14. #include "timer.h"
  15. #endif
  16.  
  17. #define PATHHOST_SEPARATOR ','        /* character used to separate hosts in the pathhost line in killfile */
  18. #define SUBJECT_SEPARATOR ','        /* character used to separate words in the subject line in killfile */
  19. #define FROM_SEPARATOR ','        /* character used to separate names in the subject line in killfile */
  20.  
  21. #define GROUP_KEEP "keep"
  22. #define GROUP_DELETE "delete"        /* word in param file parsed for on group line to signify keep or delete */
  23. #define COMMA ','            /* group separator in newsgroup line in article */
  24.  
  25. /* local function prototypes */
  26. char *get_a_chunk_mem(PMaster);
  27. int chk_msg_kill(PKillStruct, char *);
  28. char *malloc_line(int which, char *linein);
  29. int check_line(char *, char *, char *, int, int, char);
  30. void free_node(OneKill);
  31. int parse_a_file(char *, char *, POneKill);
  32. int pass_two(PKillStruct);
  33. int check_a_group(POneKill, char *, int *);
  34. char *strnstr(char *, char *);
  35. /*-------------------------------------------------------------------------*/
  36. const char *Reasons[] = {
  37.     "No Reason - major screwup",
  38.     "Over Hi-Line paramter",
  39.     "Under Low-Line parameter",
  40.     "Host in Path rejected",
  41.     "Word in Subject rejected",
  42.     "Name in From rejected",
  43.     "Not matched in Group Keep file",
  44.     "Multiple Matches/Tiebreaker Used"
  45. };
  46. enum { REASON_NONE, REASON_TOOMANYLINES, REASON_NOTENUFLINES, REASON_PATHHOST,
  47. REASON_SUBJECT, REASON_FROM, REASON_NRGRPS, REASON_NOKEEP, REASON_TIE};
  48. enum { CHECK_EXACT, CHECK_CHECK };
  49.  
  50. const struct {
  51.     int len;
  52.     char *name;
  53.     int headerlen;
  54.     char *header;
  55. } Params[] = {
  56.     {8, "HILINES=", 7, "Lines: " },
  57.     {9, "LOWLINES=", 7, "Lines: "},
  58.     {5, "PATH=", 6, "Path: " },
  59.     {8, "SUBJECT=", 9, "Subject: " },
  60.     {5, "FROM=", 6, "From: " },
  61.     {7, "NRGRPS=", 12, "Newsgroups: "},
  62.     {6, "GROUP=", 0, ""},
  63.     {6, "QUOTE=", 0, ""}
  64. };
  65. enum { PARAM_HILINE, PARAM_LOWLINE, PARAM_PATH, PARAM_SUBJ, PARAM_FROM, PARAM_NRGRPS, PARAM_GROUP, PARAM_QUOTE};
  66. #define NR_PARAMS (sizeof(Params)/sizeof(Params[0]))
  67.  
  68. enum { DELKEEP_KEEP, DELKEEP_DELETE };
  69. /*--------------------------------------------------------------------------*/
  70. PKillStruct parse_killfile() {
  71.     static KillStruct mykill;
  72.     PKillStruct retptr;
  73.     FILE *fptr;
  74.     char buf[MAXLINLEN+1];
  75.  
  76.     /* first initialize it */
  77.     mykill.nrgrps = 0;
  78.     mykill.grps = NULL;
  79.     retptr = &mykill;
  80.     /* kill file is going to get three passes, 1st one to count how many group files to process */
  81.     /* so can allocate memory for all the group stuff. */
  82.     /* 2nd pass will be to actually process the group files */
  83.     /* 3rd pass will be to process the master delete stuff */
  84.     
  85.     /* FIRST PASS THRU MASTER KILLFILE - only look for group delete/keeps and count em */
  86.     if((fptr = fopen(full_path(FP_GET, FP_DATADIR, N_KILLFILE), "r")) == NULL) {
  87.     /*    MyPerror(full_path(FP_GET, FP_DATADIR, N_KILLFILE));    */
  88.     /* this is not really an error, so don't report it as such */
  89.         retptr = NULL;
  90.     }
  91.     else {
  92. #ifdef DEBUG2
  93.         do_debug("Pass 1 kill file: %s\n", full_path(FP_GET, FP_DATADIR, N_KILLFILE));
  94. #endif
  95.         while(fgets(buf, MAXLINLEN, fptr) != NULL) {
  96. #ifdef DEBUG2
  97.             do_debug("Read kill file line: %s\n", buf);
  98. #endif
  99.             if(strncmp(buf, Params[PARAM_GROUP].name, Params[PARAM_GROUP].len) == 0) {
  100.                 mykill.nrgrps++;    /* how many group files must we process */
  101.             }            
  102.         }
  103.         fclose(fptr);
  104.  
  105.         /* SECOND PASS - call routine */
  106.         if(mykill.nrgrps > 0) {
  107.             if(pass_two(&mykill) == RETVAL_ERROR) {
  108.                 retptr = NULL;
  109.             }
  110.         }
  111.         /* THIRD PASS - process master delete stuff */
  112.         if(retptr != NULL && parse_a_file(N_KILLFILE, "Master", &(mykill.master)) != RETVAL_OK) {
  113.             retptr = NULL;
  114.         }
  115.     }
  116.  
  117.     if(retptr == NULL) {
  118.         free_killfile(&mykill);    /* just in case any memory got allocated */
  119.     }
  120.     return retptr;
  121. }
  122. /*-------------------------------------------------------------------------------------------*/
  123. int pass_two(PKillStruct killp ) {
  124.  
  125.     int retval = RETVAL_OK;
  126.     FILE *fptr;
  127.     char buf[MAXLINLEN];
  128.     int i, grpon = 0;
  129.     char *grpname, *grpfile, *delkeep;
  130.  
  131.     grpname = grpfile = delkeep = NULL;
  132.  
  133.     /* SECOND PASS - now that we know how many, we can allocate the space for em */
  134.     /* and then have parse_a_file read em in. */
  135.     if((killp->grps = calloc(killp->nrgrps, sizeof(Group))) == NULL) {
  136.         retval = RETVAL_ERROR;
  137.         error_log(ERRLOG_REPORT, "Out of memory, can't do killfiles\n");
  138.     }
  139.     else if((fptr = fopen(full_path(FP_GET, FP_DATADIR, N_KILLFILE), "r")) == NULL) {
  140.         MyPerror(full_path(FP_GET, FP_DATADIR, N_KILLFILE));
  141.         retval = RETVAL_ERROR;
  142.     }
  143.     else {
  144. #ifdef DEBUG2
  145.         do_debug("Pass 2 kill file: %s\n", full_path(FP_GET, FP_DATADIR, N_KILLFILE));
  146. #endif
  147.         while(retval == RETVAL_OK && fgets(buf, MAXLINLEN, fptr) != NULL) {
  148. #ifdef DEBUG2
  149.             do_debug("Read kill file line: %s\n", buf);
  150. #endif
  151.             if(strncmp(buf, Params[PARAM_GROUP].name, Params[PARAM_GROUP].len) == 0 ) {
  152.                 
  153.                 /* now parse the line for the 3 required elements */
  154.                 /* keep/delete group_name filename */
  155.                 delkeep = &buf[Params[PARAM_GROUP].len];
  156.                 if(strncmp(delkeep, GROUP_KEEP, strlen(GROUP_KEEP)) == 0) {
  157.                     killp->grps[grpon].delkeep = DELKEEP_KEEP;
  158.                 }
  159.                 else if(strncmp(delkeep, GROUP_DELETE, strlen(GROUP_DELETE)) == 0) {
  160.                     killp->grps[grpon].delkeep = DELKEEP_DELETE;
  161.                 }
  162.                 else {
  163.                     retval = RETVAL_ERROR;
  164.                 }
  165.                 if(retval == RETVAL_OK) {
  166.                     grpname = strchr(delkeep, ' ');    /* find the space */
  167.                     if(grpname == NULL) {
  168.                         retval = RETVAL_ERROR;
  169.                     }
  170.                     else {
  171.                         ++grpname;    /* move past space */
  172.                         grpfile = strchr(grpname, ' ');
  173.                         if(grpfile == NULL) {
  174.                             retval = RETVAL_ERROR;
  175.                         }
  176.                         else {
  177.                             *grpfile = '\0';    /* truncate the group name for easier copying later */
  178.                             ++grpfile;
  179.                         }
  180.                         /* nuke newline */
  181.                         i = strlen(grpfile) - 1;
  182.                         if(grpfile[i] == '\n') {
  183.                             grpfile[i] = '\0';
  184.                         }
  185.                     }
  186.  
  187.                 }
  188.                 if(retval == RETVAL_ERROR) {
  189.                     error_log(ERRLOG_REPORT, "Invalid Parameter Line: %s\n", buf);
  190.                 }
  191.                 else {    /* have all three params, put them in place and parse the file */
  192.                     if((killp->grps[grpon].group = malloc(strlen(grpname)+1)) == NULL) {
  193.                         error_log(ERRLOG_REPORT, "Out of Memory");
  194.                         retval = RETVAL_ERROR;
  195.                     }
  196.                     else {
  197.                         strcpy(killp->grps[grpon].group, grpname);
  198.                         retval = parse_a_file(grpfile, grpname, &(killp->grps[grpon].match));
  199.                     }
  200.                 }
  201.                 grpon++;    /* finished with this group */
  202.             }
  203.         }
  204.         fclose(fptr);
  205.     }
  206.  
  207.     return retval;
  208. }
  209. /*--------------------------------------------------------------------------*/
  210. void free_killfile(PKillStruct master) {
  211.  
  212.     int i;
  213.  
  214.     if(master != NULL) {
  215.         free_node(master->master);
  216.         if(master->nrgrps > 0) {
  217.             for(i=0;i<master->nrgrps;i++) {
  218.                 free_node(master->grps[i].match);
  219.                 free(master->grps[i].group);
  220.             }
  221.             free(master->grps);
  222.         }
  223.         if(master->master.path != NULL) {
  224.             free(master->master.path);
  225.         }
  226.     }
  227. }
  228. /*--------------------------------------------------------------------*/
  229. void free_node(OneKill node) {
  230.     if(node.path != NULL) {
  231.         free(node.path);
  232.     }
  233.     if(node.from != NULL) {
  234.         free(node.from);
  235.     }
  236.     if(node.subj != NULL) {
  237.         free(node.subj);
  238.     }
  239. }
  240. /*--------------------------------------------------------------------------*/
  241. int get_one_article_kill(PMaster master, int logcount, PKillStruct killp) {
  242.  
  243.     char buf[MAXLINLEN+1], *inbuf, *fname;
  244.     int retval;
  245.     FILE *fptr;
  246.  
  247.     retval = RETVAL_OK;
  248.  
  249.     /* build command to get article header*/
  250.     sprintf(buf, "head %s\r\n", (master->curr)->msgnr);
  251.  
  252.     switch(send_a_command(master->sockfd, buf, 221)) {
  253.       case RETVAL_ERROR:
  254.         retval = RETVAL_ERROR;
  255.         break;
  256.       case RETVAL_OK:
  257.         if((inbuf = get_a_chunk_mem(master)) == NULL) {
  258.             retval = RETVAL_ERROR;
  259.         }
  260.         else if(chk_msg_kill(killp, inbuf)==FALSE){
  261.             if(master->MultiFile == TRUE) {
  262.                 /* open file */
  263.                 /* file name will be ####-#### ex 001-166 (nron,total) */
  264.                 sprintf(buf,"%0*d-%d", logcount, master->itemon, master->nritems);
  265.                 fname = full_path(FP_GET, FP_MSGDIR, buf);
  266.                 if((fptr = fopen(fname, "w")) == NULL) {
  267.                     MyPerror(fname);
  268.                     retval = RETVAL_ERROR;
  269.                 }
  270.                 else {
  271.                     fputs(inbuf, fptr);
  272.                     fputs("\n", fptr);    /* needed */
  273.                     sprintf(buf, "body %s\r\n", (master->curr)->msgnr);
  274.                     switch(send_a_command(master->sockfd, buf, 222)) {
  275.                       case RETVAL_OK:
  276.                         retval = get_a_chunk(master->sockfd, fptr);
  277.                         break;
  278.                       case RETVAL_ERROR:
  279.                         retval = RETVAL_ERROR;
  280.                         break;
  281.                       case RETVAL_UNEXPECTEDANS:
  282.                         break;
  283.                     }
  284.                     fclose(fptr);
  285.                     if(retval != RETVAL_OK) {
  286.                         unlink(fname);
  287.                     }
  288.                 }
  289.             }
  290.             else {
  291.                 fputs(inbuf, stdout);
  292.                 fputs("\n", stdout);
  293.                 sprintf(buf, "body %s\r\n", (master->curr)->msgnr);
  294.                 switch(send_a_command(master->sockfd, buf, 222)) {
  295.                   case RETVAL_OK:
  296.                     retval = get_a_chunk(master->sockfd, stdout);
  297.                     /* this is needed as a separator */
  298.                     /* in stdout version */
  299.                     fputs(".\n", stdout);
  300.                     break;
  301.                   case RETVAL_ERROR:
  302.                     retval = RETVAL_ERROR;
  303.                     break;
  304.                   case RETVAL_UNEXPECTEDANS:
  305.                     /* nothing to do  */
  306.                     break;
  307.                 }            
  308.             
  309.             }
  310.             if(retval == RETVAL_OK) {
  311.                 master->nrgot++;
  312.             }
  313.         }
  314.         break;
  315.       case RETVAL_UNEXPECTEDANS:
  316.         break;
  317.     }
  318.     return retval;
  319. }
  320. /*---------------------------------------------------------------*/
  321. /* this routine is same as get_a_chunk() except it goes to memory */
  322. char *get_a_chunk_mem(PMaster master) {
  323.  
  324.     static char *buf = NULL;
  325.     static int bufsize = 8192;
  326.  
  327.     int retval, done, partial, len, currbuf;
  328.     char *inbuf, *newbuf;
  329.  
  330.     retval = RETVAL_OK;
  331.     done = FALSE;
  332.     partial = FALSE;
  333.     currbuf = 0;
  334.     if(buf == NULL) {
  335. #ifdef DEBUG2
  336.         do_debug("allocing memory, size = %d\n", bufsize);
  337. #endif
  338.         if((buf=malloc((size_t) bufsize)) == NULL) {
  339.             error_log(ERRLOG_REPORT, "Out of Memory");
  340.         }
  341.     }
  342.     while(buf != NULL && done == FALSE) {
  343.         len=sgetline(master->sockfd, &inbuf);
  344. #ifdef TIMER
  345.         TimerFunc(TIMER_ADDBYTES, len);
  346. #endif
  347.         if(len < 0) {
  348.             free(buf);
  349.             buf = NULL;
  350.             done = TRUE;
  351.         }
  352.         else if(partial == FALSE && inbuf[0] == '.') {
  353.             if(len == 2 && inbuf[1] == '\n') {
  354.                 done = TRUE;
  355.             }
  356.             else if(master->MultiFile == TRUE) {
  357.                 /* handle double dots IAW RFC977 2.4.1*/
  358.                 /* don't do if we aren't doing multifile, since */
  359.                 /* stdout needs the .. to distinguish dots and EOM */
  360.                 inbuf++;    /* move past first dot */
  361.                 len--;
  362.             }
  363.         }
  364.         if(done == FALSE) {
  365.             if((len+currbuf) > bufsize) {
  366.                 /* buffer not big enough realloc */
  367.                 bufsize = len+currbuf;
  368.                 if((newbuf = realloc(buf, (size_t) bufsize)) == NULL) {
  369.                     free(buf);
  370.                     buf = NULL;
  371.                     error_log(ERRLOG_REPORT, "Out of Memory");
  372. #ifdef DEBUG2
  373.                     do_debug("Re-alloc failed\n");
  374. #endif
  375.                 }
  376.                 else {
  377.                     buf = newbuf;
  378. #ifdef DEBUG2
  379.                     do_debug("Re-alloc succeeded, new size = %d\n", bufsize);
  380. #endif
  381.                 }
  382.             }    
  383.             if(buf != NULL) {
  384.                 strcpy(buf+currbuf, inbuf);
  385.                 currbuf += len;
  386.                 partial= (len==MAXLINLEN&&inbuf[len-1]!='\n') ? TRUE : FALSE;
  387.             }
  388.         }
  389.     }
  390.     return buf;
  391. }
  392. /*-------------------------------------------------------------------------*/
  393. /* chk_msg_kill - return TRUE if kill article, FALSE if keep                   */
  394. /* if kill article, add it to killlog                        */
  395. int chk_msg_kill(PKillStruct killp, char *headerbuf) {
  396.  
  397.     int why, goodwhy, killyn, i, del, keep, match;
  398.     char *group = "Master";
  399.  
  400. #ifdef KILLFILE_LOG
  401.     FILE *fptr;
  402. #endif
  403.  
  404.     goodwhy = why = REASON_NONE;
  405.  
  406.     /* first check against master delete */
  407.     if((killyn = check_a_group(&(killp->master), headerbuf, &why)) == FALSE) {
  408.         /* okay now have to parse group line */
  409.         /* then check to see if I have group keep/deletes for each group */
  410.         /* default actions */
  411.          keep = FALSE;
  412.         del = FALSE;
  413.         for(i=0;i<killp->nrgrps;i++) {
  414.             if(check_line(headerbuf, "Newsgroups: ", killp->grps[i].group, ',', CHECK_EXACT, ' ') == TRUE) {
  415.                 /* bingo this article matches one of our group check it */
  416.                 match = check_a_group(&(killp->grps[i].match), headerbuf, &why);
  417.                 if(killp->grps[i].delkeep == DELKEEP_KEEP) {
  418.                     /* matched keep group */
  419.                     if(match == TRUE) {
  420.                         keep = TRUE;
  421.                     }
  422.                     else {
  423.                         del = TRUE;
  424.                         group = killp->grps[i].group;
  425.                         goodwhy = REASON_NOKEEP;
  426.                     }
  427.                 }
  428.                 else {
  429.                     if(match == TRUE) {
  430.                         del = TRUE;
  431.                         goodwhy = why;
  432.                         group = killp->grps[i].group;
  433.                     }
  434.                     else {
  435.                         keep = TRUE;
  436.                     }
  437.                 }
  438.             }
  439.         }
  440.         /* now determine if we kill or keep this sucker */
  441.         if(keep == FALSE && del == FALSE) {
  442.             /* no group matches, keep it */
  443.             killyn = FALSE;
  444.         }
  445.         else if(keep != del) {
  446.             /* only matched one group, figure out which */
  447.             killyn = ( del == TRUE) ? TRUE : FALSE;
  448.             why = goodwhy;
  449.         }
  450.         else {
  451.             /* matched both, use TIEBREAKER */
  452.             why = REASON_TIE;
  453. #ifdef KILL_TIEBREAKER_KEEP
  454.             killyn = FALSE;
  455. #else
  456.             killyn = TRUE;
  457. #endif
  458.         }
  459.     }
  460. #ifdef KILLFILE_LOG
  461.     if(killyn == TRUE) {
  462.         /* log it */
  463.         if((fptr = fopen(full_path(FP_GET, FP_TMPDIR, N_KILLLOG), "a")) == NULL) {
  464.             MyPerror("Unable to log killed article");
  465.         }
  466.         else {
  467.             fprintf(fptr, "ARTICLE KILLED: %s - %s\n%s\n", group, Reasons[why], headerbuf);
  468.             fclose(fptr);
  469.         }
  470.     }
  471. #endif
  472.     return killyn;            
  473. }
  474. /*-----------------------------------------------------------------------*/
  475. int check_a_group(POneKill killp, char *headerbuf, int *why) {
  476.  
  477.     int i, match = FALSE;
  478.     char *startline, *tptr;
  479.     
  480.     /* check hilines first */
  481.     if(killp->hilines > 0) { 
  482.         if((startline = strstr(headerbuf, Params[PARAM_HILINE].header)) != NULL)  {
  483.             i = 0;    /* just in case */
  484.             sscanf(startline+Params[PARAM_HILINE].headerlen, "%d", &i);
  485. #ifdef DEBUG2
  486.             do_debug("Article has %d lines, hilines = %d\n", i, killp->hilines);
  487. #endif
  488.             if(killp->hilines < i) {
  489.                 /* JACKPOT */
  490.                 match = TRUE;
  491.                 *why = REASON_TOOMANYLINES;
  492.             }
  493.         }
  494.         
  495.     }
  496.     /* now check low lines */
  497.     if(match == FALSE && killp->lowlines > 0) { 
  498.         if((startline = strstr(headerbuf, Params[PARAM_LOWLINE].header)) != NULL)  {
  499.             i = 0;    /* just in case */
  500.             sscanf(startline+Params[PARAM_LOWLINE].headerlen, "%d", &i);
  501. #ifdef DEBUG2
  502.             do_debug("Article has %d lines, lowlines = %d\n", i, killp->lowlines);
  503. #endif
  504.             if(i < killp->lowlines) {
  505.                 /* JACKPOT */
  506.                 match = TRUE;
  507.                 *why = REASON_NOTENUFLINES;
  508.             }
  509.         }
  510.         
  511.     }
  512.     /* now check nrgrps */
  513.     if(match == FALSE && killp->nrgrps > 0) {
  514.         if((startline = strstr(headerbuf, Params[PARAM_NRGRPS].header)) != NULL) {
  515.             /* count the nr of commas in the group line */
  516.             i = 1;    /* have at least one group */
  517.             tptr = startline;
  518.             while(i <= killp->nrgrps && *tptr != '\0' ) {
  519.                 if(*tptr++ == COMMA) {
  520.                     i++;
  521.                 }
  522.             }
  523.             if(i >= killp->nrgrps) {
  524.                 match = TRUE;
  525.                 *why = REASON_NRGRPS;
  526.             }        
  527.         }
  528.     }
  529.     /* check host */
  530.     if(match == FALSE && killp->path != NULL) {
  531.         if(check_line(headerbuf, Params[PARAM_PATH].header, killp->path, PATHHOST_SEPARATOR, CHECK_CHECK, killp->quote) == TRUE) {
  532.             /* jackpot */
  533.             match = TRUE;
  534.             *why = REASON_PATHHOST;
  535.         }
  536.     }
  537.     /* check from */
  538.     if(match == FALSE && killp->from != NULL) {
  539.         if(check_line(headerbuf, Params[PARAM_FROM].header, killp->from, FROM_SEPARATOR, CHECK_CHECK, killp->quote) == TRUE) {
  540.             /* jackpot */
  541.             match = TRUE;
  542.             *why = REASON_FROM;
  543.         }
  544.     }
  545.     /* check subject */
  546.     if(match == FALSE && killp->subj != NULL) {
  547.         if(check_line(headerbuf, Params[PARAM_SUBJ].header, killp->subj, SUBJECT_SEPARATOR, CHECK_CHECK, killp->quote) == TRUE) {
  548.             /* jackpot */
  549.             match = TRUE;
  550.             *why = REASON_SUBJECT;
  551.         }
  552.     }
  553.     return match;
  554. }
  555. /*-----------------------------------------------------------------------*/
  556. char *malloc_line(int which, char *linein) {
  557.  
  558.     /* malloc and copy a header line WITHOUT the header field */
  559.     char *ptr;
  560.     int x;
  561.  
  562.                        /* len = how much not to malloc */
  563.     if((ptr = malloc((strlen(linein)+1) - Params[which].len)) == NULL) {
  564.         error_log(ERRLOG_REPORT, "Unable to malloc memory\n");
  565.     } 
  566.     else {
  567.         strcpy(ptr, &linein[Params[which].len]);
  568.         /* strip the newline, if present */
  569.         x = strlen(ptr);
  570.         if(ptr[x-1] == '\n') {
  571.             ptr[x-1] = '\0';
  572.         }
  573.     }
  574.     return ptr;
  575. }
  576. /*--------------------------------------------------------------------------*/
  577. int check_line(char *header, char *whichline, char *linematch, int separator, int check_quote, char quote_char) {
  578.     /* search for each item in linematch on whichline in the header */
  579.     /* if check_quote = CHECK_CHECK check if first char is char_quote */
  580.     /* if it is, then do strcmp, else do a strncmp */
  581.     /* if check_quote = CHECK_EXACT don't check first char just strcmp */
  582.  
  583.     char *startline, *endline, *currcomma, *nextcomma;
  584.     int casecmp, match = FALSE;
  585.  
  586.     
  587.     if((startline = strstr(header, whichline)) != NULL) {
  588.         currcomma = linematch;    /* start us off */
  589.         endline = strchr(startline, '\n');    
  590.         /* end this line, so we only search the right header line */
  591.         if(endline != NULL) {
  592.             *endline = '\0';
  593.         }
  594.         do { 
  595.             nextcomma = strchr(currcomma, separator);
  596.             if(nextcomma != NULL) {
  597.                 *nextcomma = '\0';    /* null terminate current entry in linematch */
  598.             }
  599. #ifdef DEBUG2
  600.             do_debug("Checking %s for \"%s\"\n", whichline, currcomma);
  601. #endif
  602.             /* now set the case comparison flag for this string */
  603.             casecmp = (check_quote == CHECK_EXACT) ? TRUE : FALSE;
  604.             if(check_quote == CHECK_CHECK) { 
  605.                 if(*currcomma == quote_char) {
  606.                     casecmp = TRUE;
  607.                     currcomma++;
  608.                 }
  609.             }
  610.             if(casecmp == TRUE) {
  611.                 if(strstr(startline, currcomma) != NULL) {
  612.                     /* jackpot */
  613.                     match = TRUE;
  614.                 }
  615.             }
  616.             else if(strnstr(startline, currcomma) != NULL) {
  617.                 match = TRUE;
  618.             }
  619.             if(nextcomma != NULL) {
  620.                 *nextcomma = separator;        /* must restore */
  621.                 currcomma = nextcomma+1;    /* check next +1 to move past comma */
  622.             }
  623.         }
  624.         while(nextcomma != NULL && match == FALSE);
  625.         if(endline != NULL) {    /* restore previously nuked nl */
  626.             *endline ='\n';
  627.         }
  628.     }
  629.     return match;
  630. }
  631. /*-------------------------------------------------------------------------------*/
  632. int parse_a_file(char *fname, char *group, POneKill mykill) {
  633.  
  634.     FILE *fptr;
  635.     char buf[MAXLINLEN+1];
  636.     int i;
  637.     int retval = RETVAL_OK;
  638.  
  639.     /* first initialized the killstruct */
  640.     mykill->hilines = mykill->lowlines = mykill->nrgrps = 0;
  641.     mykill->path = mykill->from = mykill->subj = NULL;
  642.     mykill->quote = KILLFILE_QUOTE;
  643.  
  644.     /* now read in the killfile and parse it */
  645.     if((fptr = fopen(full_path(FP_GET, FP_DATADIR, fname), "r")) == NULL) {
  646.         MyPerror(full_path(FP_GET, FP_DATADIR, fname));
  647.         retval = RETVAL_ERROR;
  648.     }
  649.     else {
  650. #ifdef DEBUG2
  651.         do_debug("Opening kill file: %s\n", full_path(FP_GET, FP_DATADIR, fname));
  652. #endif
  653.  
  654.         while(fgets(buf, MAXLINLEN, fptr) != NULL) {
  655. #ifdef DEBUG2
  656.             do_debug("Read kill file line: %s\n", buf);
  657. #endif
  658.             buf[MAXLINLEN] = 0;    /* just in case */
  659.  
  660.             for(i = 0 ; i < NR_PARAMS; i++) {
  661.                 if(strncmp(buf, Params[i].name, Params[i].len) == 0) {
  662.                     switch(i) {
  663.                       case PARAM_HILINE:
  664.                         sscanf(&buf[Params[PARAM_HILINE].len], "%d", &(mykill->hilines));
  665. #ifdef DEBUG2
  666.                         do_debug("Killfile hilines = %d\n", mykill->hilines);
  667. #endif
  668.                         break;
  669.                       case PARAM_LOWLINE:
  670.                         sscanf(&buf[Params[PARAM_LOWLINE].len], "%d", &(mykill->lowlines));
  671. #ifdef DEBUG2
  672.                         do_debug("Killfile lowlines = %d\n", mykill->lowlines);
  673. #endif
  674.                         break;
  675.                       case PARAM_NRGRPS:
  676.                         sscanf(&buf[Params[PARAM_NRGRPS].len], "%d", &(mykill->nrgrps));
  677. #ifdef DEBUG2
  678.                         do_debug("Killfile nrgrps = %d\n", mykill->nrgrps);
  679. #endif
  680.                         break;                        
  681.                       case PARAM_PATH:
  682.                         if((mykill->path = malloc_line(PARAM_PATH, buf)) == NULL) {
  683.                             error_log(ERRLOG_REPORT, "No paths will be processed for %s\n", group);
  684.                         }
  685. #ifdef DEBUG2 
  686.                         else {
  687.                             do_debug("Killfile path = %s\n", mykill->path);
  688.                         }
  689. #endif
  690.                         break;
  691.                       case PARAM_FROM:
  692.                         if((mykill->from = malloc_line(PARAM_FROM, buf)) == NULL) {
  693.                             error_log(ERRLOG_REPORT, "No From lines will be processed for %s\n", group);
  694.                         }
  695. #ifdef DEBUG2 
  696.                         else {
  697.                             do_debug("Killfile from = %s\n", mykill->from);
  698.                         }
  699. #endif
  700.                         break;
  701.                       case PARAM_SUBJ:
  702.                         if((mykill->subj = malloc_line(PARAM_SUBJ, buf)) == NULL) {
  703.                             error_log(ERRLOG_REPORT, "No Subjects will be processed for %s\n", group);
  704.                         }
  705. #ifdef DEBUG2 
  706.                         else {
  707.                             do_debug("Killfile Subject = %s\n", mykill->subj);
  708.                         }
  709. #endif
  710.                         break;
  711.                       case PARAM_QUOTE:
  712.                         if(buf[Params[PARAM_QUOTE].len] == '\0' && buf[Params[PARAM_QUOTE].len] == '\n') {
  713.                             error_log(ERRLOG_REPORT, "No character to process for quote, ignoring\n");
  714.                         }
  715.                         else {
  716.                             mykill->quote = buf[Params[PARAM_QUOTE].len];
  717. #ifdef DEBUG2
  718.                             do_debug("Killfile Quote = '%c'\n", mykill->quote);
  719. #endif
  720.                         }
  721.                         break;
  722.                       default:    /* ignore group lines, those processed elsewhere */
  723.                         break;
  724.                       
  725.                     }
  726.                 }
  727.             }
  728.         }
  729.         fclose(fptr);
  730.     }
  731.     return retval;
  732. }
  733. /*---------------------------------------------------------------------------------------------*/
  734. char *strnstr(char *linein, char *matchstr) {
  735.  
  736.     /* see if matchstr exists in inline, case insensitive */
  737.     /* return start of string in inline, else return NULL */
  738.  
  739.     char *tptr, *startchar, *retstr = NULL;
  740.     
  741.     if(linein != NULL && matchstr != NULL) {
  742.         while(*linein != '\0' && retstr == NULL) {
  743.             /* first see if I can find the first char */
  744.             while(*linein != '\0' && tolower(*linein) != tolower(*matchstr)) {
  745.                 linein++;
  746.             }
  747.             if(*linein != '\0') {
  748.                 /* bingo */
  749.                 startchar = linein;
  750.                 /* now try to match rest of string */
  751.                 tptr = matchstr;
  752.                 while(tolower(*startchar) == tolower(*tptr) && *tptr != '\0') {
  753.                     startchar++;
  754.                     tptr++;
  755.                 }
  756.                 if(*tptr == '\0') {
  757.                     /* bingo, we have a match */
  758.                     retstr =  linein;
  759.                 }
  760.                 else {
  761.                     /* no match */
  762.                     linein++;
  763.                 }
  764.             }        
  765.         }
  766.     }
  767.     return retstr;
  768. }
  769.